From 366b4db791b03b39275c6767dede2c2089f40506 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Wed, 6 Feb 2013 14:29:22 +0100 Subject: [PATCH] css: Support opacity https://bugzilla.gnome.org/show_bug.cgi?id=687842 --- gtk/gtkcssstylepropertyimpl.c | 16 ++++++ gtk/gtkcsstypesprivate.h | 1 + gtk/gtkwidget.c | 101 ++++++++++++++++++++++------------ 3 files changed, 83 insertions(+), 35 deletions(-) diff --git a/gtk/gtkcssstylepropertyimpl.c b/gtk/gtkcssstylepropertyimpl.c index c58edd85e1..26726d73d7 100644 --- a/gtk/gtkcssstylepropertyimpl.c +++ b/gtk/gtkcssstylepropertyimpl.c @@ -420,6 +420,14 @@ parse_css_direction (GtkCssStyleProperty *property, return _gtk_css_array_value_parse (parser, parse_one_css_direction); } +static GtkCssValue * +opacity_parse (GtkCssStyleProperty *property, + GtkCssParser *parser) +{ + return _gtk_css_number_value_parse (parser, GTK_CSS_PARSE_NUMBER); +} + + static GtkCssValue * parse_one_css_play_state (GtkCssParser *parser) { @@ -1382,6 +1390,14 @@ _gtk_css_style_property_init_properties (void) NULL, NULL, _gtk_css_array_value_new (_gtk_css_fill_mode_value_new (GTK_CSS_FILL_NONE))); + gtk_css_style_property_register ("opacity", + GTK_CSS_PROPERTY_OPACITY, + G_TYPE_NONE, + GTK_STYLE_PROPERTY_ANIMATED | GTK_STYLE_PROPERTY_NO_RESIZE, + opacity_parse, + NULL, + NULL, + _gtk_css_number_value_new (1, GTK_CSS_NUMBER)); gtk_css_style_property_register ("engine", GTK_CSS_PROPERTY_ENGINE, diff --git a/gtk/gtkcsstypesprivate.h b/gtk/gtkcsstypesprivate.h index 9c1f92ba2b..b2881feaea 100644 --- a/gtk/gtkcsstypesprivate.h +++ b/gtk/gtkcsstypesprivate.h @@ -132,6 +132,7 @@ enum { /*< skip >*/ GTK_CSS_PROPERTY_ANIMATION_PLAY_STATE, GTK_CSS_PROPERTY_ANIMATION_DELAY, GTK_CSS_PROPERTY_ANIMATION_FILL_MODE, + GTK_CSS_PROPERTY_OPACITY, GTK_CSS_PROPERTY_ENGINE, GTK_CSS_PROPERTY_GTK_KEY_BINDINGS, /* add more */ diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index a2faff55e1..d99ee5552e 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -37,6 +37,7 @@ #include "gtkaccelmapprivate.h" #include "gtkclipboard.h" #include "gtkcssstylepropertyprivate.h" +#include "gtkcssnumbervalueprivate.h" #include "gtkiconfactory.h" #include "gtkintl.h" #include "gtkmarshalers.h" @@ -362,6 +363,7 @@ struct _GtkWidgetPrivate guint norender : 1; /* Don't expose windows, instead recurse via draw */ guint8 alpha; + guint8 user_alpha; /* The widget's name. If the widget does not have a name * (the name is NULL), then its name (as returned by @@ -610,7 +612,8 @@ static PangoContext* gtk_widget_peek_pango_context (GtkWidget *widget); static void gtk_widget_update_pango_context (GtkWidget *widget); static void gtk_widget_propagate_state (GtkWidget *widget, GtkStateData *data); -; +static void gtk_widget_update_alpha (GtkWidget *widget); + static gint gtk_widget_event_internal (GtkWidget *widget, GdkEvent *event); static gboolean gtk_widget_real_mnemonic_activate (GtkWidget *widget, @@ -3743,6 +3746,7 @@ gtk_widget_init (GtkWidget *widget) priv->allocation.y = -1; priv->allocation.width = 1; priv->allocation.height = 1; + priv->user_alpha = 255; priv->alpha = 255; priv->window = NULL; priv->parent = NULL; @@ -6801,6 +6805,7 @@ gtk_widget_real_style_updated (GtkWidget *widget) GtkWidgetPrivate *priv = widget->priv; gtk_widget_update_pango_context (widget); + gtk_widget_update_alpha (widget); if (priv->style != NULL && priv->style != gtk_widget_get_default_style ()) @@ -13927,55 +13932,37 @@ gtk_widget_update_norender (GtkWidget *widget) propagate_norender_non_window (widget, norender | widget->priv->norender_children); } -/** - * gtk_widget_set_opacity: - * @widget: a #GtkWidget - * @opacity: desired opacity, between 0 and 1 - * - * Request the @widget to be rendered partially transparent, - * with opacity 0 being fully transparent and 1 fully opaque. (Opacity values - * are clamped to the [0,1] range.). - * This works on both toplevel widget, and child widgets, although there - * are some limitations: - * - * For toplevel widgets this depends on the capabilities of the windowing - * system. On X11 this has any effect only on X screens with a compositing manager - * running. See gtk_widget_is_composited(). On Windows it should work - * always, although setting a window's opacity after the window has been - * shown causes it to flicker once on Windows. - * - * For child widgets it doesn't work if any affected widget has a native window, or - * disables double buffering. - * - * Since: 3.8 - **/ -void -gtk_widget_set_opacity (GtkWidget *widget, - gdouble opacity) +static void +gtk_widget_update_alpha (GtkWidget *widget) { GtkWidgetPrivate *priv; + double opacity; guint8 alpha; - g_return_if_fail (GTK_IS_WIDGET (widget)); - priv = widget->priv; - if (opacity < 0.0) - opacity = 0.0; - else if (opacity > 1.0) - opacity = 1.0; + alpha = priv->user_alpha; + + if (priv->context) + { + opacity = + _gtk_css_number_value_get (_gtk_style_context_peek_property (priv->context, + GTK_CSS_PROPERTY_OPACITY), + 100); + opacity = CLAMP (opacity, 0.0, 1.0); + alpha = round (priv->user_alpha * opacity); + } - alpha = round (opacity * 255); if (alpha == priv->alpha) return; priv->alpha = alpha; - if (gtk_widget_get_has_window (widget)) + if (gtk_widget_get_has_window (widget)) { if (priv->window != NULL) gdk_window_set_opacity (priv->window, - priv->norender ? 0 : opacity); + priv->norender ? 0 : priv->alpha / 255.0); } else { @@ -14004,6 +13991,50 @@ gtk_widget_set_opacity (GtkWidget *widget, gtk_widget_queue_draw (widget); } +/** + * gtk_widget_set_opacity: + * @widget: a #GtkWidget + * @opacity: desired opacity, between 0 and 1 + * + * Request the @widget to be rendered partially transparent, + * with opacity 0 being fully transparent and 1 fully opaque. (Opacity values + * are clamped to the [0,1] range.). + * This works on both toplevel widget, and child widgets, although there + * are some limitations: + * + * For toplevel widgets this depends on the capabilities of the windowing + * system. On X11 this has any effect only on X screens with a compositing manager + * running. See gtk_widget_is_composited(). On Windows it should work + * always, although setting a window's opacity after the window has been + * shown causes it to flicker once on Windows. + * + * For child widgets it doesn't work if any affected widget has a native window, or + * disables double buffering. + * + * Since: 3.8 + **/ +void +gtk_widget_set_opacity (GtkWidget *widget, + gdouble opacity) +{ + GtkWidgetPrivate *priv; + guint8 alpha; + + g_return_if_fail (GTK_IS_WIDGET (widget)); + + priv = widget->priv; + + opacity = CLAMP (opacity, 0.0, 1.0); + + alpha = round (opacity * 255); + if (alpha == priv->user_alpha) + return; + + priv->user_alpha = alpha; + + gtk_widget_update_alpha (widget); +} + /** * gtk_widget_get_opacity: * @widget: a #GtkWidget -- 2.30.2